package com.ncmem.up6.store.cos;

import com.ncmem.up6.model.FileInf;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.utils.IOUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class CosTool {

    // 创建 COSClient 实例，这个实例用来后续调用请求
    static COSClient createCOSClient() {
        CosConfig cfg = new CosConfig();
        // 设置用户身份信息。
        // SECRETID 和 SECRETKEY 请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理
        COSCredentials cred = new BasicCOSCredentials(cfg.ak, cfg.sk);

        // ClientConfig 中包含了后续请求 COS 的客户端设置：
        ClientConfig clientConfig = new ClientConfig();

        // 设置 bucket 的地域
        // COS_REGION 请参照 https://cloud.tencent.com/document/product/436/6224
        clientConfig.setRegion(new Region(cfg.region));

        // 设置请求协议, http 或者 https
        // 5.6.53 及更低的版本，建议设置使用 https 协议
        // 5.6.54 及更高版本，默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);

        // 以下的设置，是可选的：

        // 设置 socket 读取超时，默认 30s
        //clientConfig.setSocketTimeout(30*1000);
        // 设置建立连接超时，默认 30s
        //clientConfig.setConnectionTimeout(30*1000);

        // 如果需要的话，设置 http 代理，ip 以及 port
        //clientConfig.setHttpProxyIp("httpProxyIp");
        //clientConfig.setHttpProxyPort(80);

        // 生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }

    /**
     * API：
     * 	https://cloud.tencent.com/document/product/436/65935
     * @param key 文件名称,QQ.exe
     * @param data
     */
    public static String putObject(String key,byte[] data) throws IOException{
        CosConfig cfg = new CosConfig();
        // 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例，如果没有则创建
        // 详细代码参见本页：简单操作 -> 创建 COSClient
        COSClient c = createCOSClient();

        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        // 对象键(Key)是对象在存储桶中的唯一标识。
        // 本地文件路径
        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentLength(data.length);

        ByteArrayInputStream ins = new ByteArrayInputStream(data);
        PutObjectRequest req = new PutObjectRequest(cfg.bucket, key, ins,meta);

        // 设置存储类型（如有需要，不需要请忽略此行代码）, 默认是标准(Standard), 低频(standard_ia)
        // 更多存储类型请参见 https://cloud.tencent.com/document/product/436/33417
        req.setStorageClass(StorageClass.Standard_IA);

        try {
            PutObjectResult res = c.putObject(req);
            String id =res.getRequestId();
            c.shutdown();
            System.out.println("cos putObject ID:" + id);
            return id;
        } catch (CosServiceException e) {
            e.printStackTrace();
            throw  new IOException("cos putObject error");
        } catch (CosClientException e) {
            e.printStackTrace();
            throw  new IOException("cos putObject error");
        }
        // 确认本进程不再使用 cosClient 实例之后，关闭之
    }

    /**
     * API：
     * 	https://cloud.tencent.com/document/product/436/65937
     * @param key 以左斜杠开始的资源路径。/guid/QQ.exe径
     * @param blockOffset
     * @param blockLen
     * @return
     */
    public static byte[] getObject(String key,long blockOffset,long blockLen)throws IOException
    {
        CosConfig cfg = new CosConfig();
        // 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例，如果没有则创建
        // 详细代码参见本页：简单操作 -> 创建 COSClient
        COSClient cosClient = createCOSClient();

        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        // 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
        GetObjectRequest req = new GetObjectRequest(cfg.bucket, key);
        req.setRange(blockOffset,blockOffset+blockLen-1);
        COSObjectInputStream cosObjectInput = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        try {
            COSObject cosObject = cosClient.getObject(req);
            cosObjectInput = cosObject.getObjectContent();
            byte[] bytes = IOUtils.toByteArray(cosObjectInput);
            bos.write(bytes,0,bytes.length);
        } catch (CosServiceException e) {
            e.printStackTrace();
            throw new IOException("cos getObject error");
        } catch (CosClientException e) {
            e.printStackTrace();
            throw new IOException("cos getObject error");
        } catch (IOException e) {
            e.printStackTrace();
            throw new IOException("cos getObject error");
        }
        finally {
            // 用完流之后一定要调用 close()
            cosObjectInput.close();
        }

        // 在流没有处理完之前，不能关闭 cosClient
        // 确认本进程不再使用 cosClient 实例之后，关闭之
        cosClient.shutdown();
        return bos.toByteArray();
    }

    /**
     * API：
     * 	https://cloud.tencent.com/document/product/436/65935
     * @param key guid/QQ.exe，
     * @return
     */
    public static String CreateMultipartUpload(String key) throws IOException {
        String id = "";
        CosConfig cfg = new CosConfig();

        // 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例，如果没有则创建
        // 详细代码参见本页：简单操作 -> 创建 COSClient
        COSClient cosClient = createCOSClient();
        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        // 对象键(Key)是对象在存储桶中的唯一标识。

        InitiateMultipartUploadRequest req = new InitiateMultipartUploadRequest(cfg.bucket, key);

        // 分块上传的过程中，仅能通过初始化分块指定文件上传之后的metadata
        // 需要的头部可以在这里指定
        ObjectMetadata objectMetadata = new ObjectMetadata();
        req.setObjectMetadata(objectMetadata);

        try {
            InitiateMultipartUploadResult res = cosClient.initiateMultipartUpload(req);
            // 获取uploadid
            id = res.getUploadId();
            System.out.println("cos CreateMultipartUpload uploadID:"+id);
        } catch (CosServiceException e) {
            e.printStackTrace();
            throw new IOException("cos CreateMultipartUpload error");
        } catch (CosClientException e) {
            e.printStackTrace();
            throw new IOException("cos CreateMultipartUpload error");
        }
        return id;
    }

    /**
     * API:
     * 	https://help.aliyun.com/document_detail/84786.html
     * @param key /guid/QQ.exe
     * @param data
     */
    public static String UploadPart(String key, int part,String uploadID, byte[] data) throws IOException {
        CosConfig cfg = new CosConfig();

        // 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例，如果没有则创建
        // 详细代码参见本页：简单操作 -> 创建 COSClient
        COSClient cosClient = createCOSClient();
        // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
        // 对象键(Key)是对象在存储桶中的唯一标识。
        // uploadId 是一次分块上传任务的唯一标识，通过初始化分块上传或者查询分块上传任务获得

        // 这里创建一个 ByteArrayInputStream 来作为示例，实际中这里应该是您要上传的 InputStream 类型的流
        long inputStreamLength = 1024 * 1024;
        //byte data[] = new byte[inputStreamLength];
        InputStream ins = new ByteArrayInputStream(data);

        UploadPartRequest req = new UploadPartRequest();
        req.setBucketName(cfg.bucket);
        req.setKey(key);
        req.setUploadId(uploadID);
        req.setInputStream(ins);
        // 设置分块的长度
        req.setPartSize(data.length);
        // 设置要上传的分块编号，从 1 开始
        req.setPartNumber(part);

        try {
            UploadPartResult res = cosClient.uploadPart(req);
            PartETag etag = res.getPartETag();
            System.out.println("cos part etag:"+etag.getETag());
            return etag.getETag();
        } catch (CosServiceException e) {
            e.printStackTrace();
            throw new IOException("cos upload part error");
        } catch (CosClientException e) {
            e.printStackTrace();
            throw new IOException("cos upload part error");
        }
    }

    /**
     * 参数：pathSvr,minio_id(UploadId)
     * API:
     * 	https://cloud.tencent.com/document/product/436/65935
     * POST /Key+?uploadId=UploadId HTTP/1.1
     Host: Bucket.s3.amazonaws.com
     <?xml version="1.0" encoding="UTF-8"?>
     <CompleteMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
     <Part>
     <ChecksumCRC32>string</ChecksumCRC32>
     <ChecksumCRC32C>string</ChecksumCRC32C>
     <ChecksumSHA1>string</ChecksumSHA1>
     <ChecksumSHA256>string</ChecksumSHA256>
     <ETag>string</ETag>
     <PartNumber>integer</PartNumber>
     </Part>
     ...
     </CompleteMultipartUpload>

     * @param file
     */
    public static boolean CompleteMultipartUpload(FileInf file) throws IOException {
        CosConfig cfg = new CosConfig();
        // 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例，如果没有则创建
        // 详细代码参见本页：简单操作 -> 创建 COSClient
        COSClient c = createCOSClient();

        // 分片上传结束后，调用complete完成分片上传
        CompleteMultipartUploadRequest req =
                new CompleteMultipartUploadRequest(cfg.bucket,file.ObsKey(), file.object_id, file.etagsCos());
        try {
            CompleteMultipartUploadResult res = c.completeMultipartUpload(req);
            System.out.println(res.getRequestId());
            return true;
        } catch (CosServiceException e) {
            e.printStackTrace();
            throw new IOException("cos CompleteMultipartUpload error");
        } catch (CosClientException e) {
            e.printStackTrace();
            throw new IOException("cos CompleteMultipartUpload error");
        }finally {
            c.shutdown();
        }
    }
}
